unit ClickIt;
interface                                                                    

uses
  FastShareMem, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, //Form
  Dialogs, SynEditHighlighter, SynHighlighterCpp, SynEdit, SynMemo,
  SynHighlighterPas, StdCtrls, uPSComponent, uPSComponentExt,                            //Highlighter+engine
  SynHighlighterMulti, Buttons, Menus, AboutForm, uPSComponent_Controls,
  uPSComponent_StdCtrls, uPSComponent_Forms, uPSComponent_Default,
  SynEditMiscClasses, SynEditRegexSearch, uPSCompiler,
  ImgList, SynEditSearch, PickColor, StrUtils, Math,
  ///////////////////////////////////////////////////////////////////////////////
  PacocStringManipulation, PacocColourFinders, PacocFileManipulation,
  SynCompletionProposal, PacocMaths, PacocInput, SynHighlighterURI,
  SynURIOpener, SynEditOptionsDialog, PacocUI, DebugForm;

type
  TPacocThread = class(TThread)
  Protected
    Procedure Execute; Override;
  end;
  TMainForm = class(TForm)
    PacocSynEdit: TSynMemo;
    SynPasSyn1: TSynPasSyn;
    DebugMemo: TMemo;
    ce: TPSScriptExtension;
    btnRun: TButton;
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    About1: TMenuItem;
    mnF1Quit: TMenuItem;
    PSImport_Classes1: TPSImport_Classes;
    PSImport_DateUtils1: TPSImport_DateUtils;
    PSImport_Forms1: TPSImport_Forms;
    PSImport_StdCtrls1: TPSImport_StdCtrls;
    PSImport_Controls1: TPSImport_Controls;
    SpeedButton1: TSpeedButton;
    SpeedButton2: TSpeedButton;
    SynCompletionProposal1: TSynCompletionProposal;
    btnPause: TButton;
    SynURIOpener1: TSynURIOpener;
    SynURISyn1: TSynURISyn;
    SynMultiSyn1: TSynMultiSyn;
    SynEditSearch1: TSynEditSearch;
    btnStop: TButton;
    ImageList1: TImageList;
    PopupMenu1: TPopupMenu;
    Undo: TMenuItem;
    Redo: TMenuItem;
    N1: TMenuItem;
    Cut: TMenuItem;
    Copy: TMenuItem;
    Paste: TMenuItem;
    Delete: TMenuItem;
    N2: TMenuItem;
    Selectall: TMenuItem;
    N3: TMenuItem;
    oggleBookmarks1: TMenuItem;
    Bookmark1: TMenuItem;
    Bookmark11: TMenuItem;
    Bookmark21: TMenuItem;
    Bookmark31: TMenuItem;
    Bookmark41: TMenuItem;
    Bookmark51: TMenuItem;
    Bookmark61: TMenuItem;
    Bookmark71: TMenuItem;
    Bookmark81: TMenuItem;
    Bookmark91: TMenuItem;
    GotoBookmarks1: TMenuItem;
    Bookmark01: TMenuItem;
    Bookmark12: TMenuItem;
    Bookmark22: TMenuItem;
    Bookmark32: TMenuItem;
    Bookmark42: TMenuItem;
    Bookmark52: TMenuItem;
    Bookmark62: TMenuItem;
    Bookmark72: TMenuItem;
    Bookmark82: TMenuItem;
    Bookmark92: TMenuItem;
    View1: TMenuItem;
    mnDebug: TMenuItem;
    lbFunctions: TListBox;
    procedure btnRunClick(Sender: TObject);
    procedure ceCompile(Sender: TPSScript);
    procedure mnF1QuitClick(Sender: TObject);
    procedure About1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure SpeedButton1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure SpeedButton1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure SpeedButton2Click(Sender: TObject);
    procedure HandlePlugins(ce : TPSScript);
    procedure PacocSynEditGutterClick(Sender: TObject;
      Button: TMouseButton; X, Y, Line: Integer; Mark: TSynEditMark);
    procedure ceBreakpoint(Sender: TObject; const FileName: String;
      Position, Row, Col: Cardinal);
    procedure PacocSynEditMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure btnPauseClick(Sender: TObject);
    procedure btnStopClick(Sender: TObject);
    procedure PacocSynEditDblClick(Sender: TObject);
    procedure UndoClick(Sender: TObject);
    procedure RedoClick(Sender: TObject);
    procedure CutClick(Sender: TObject);
    procedure CopyClick(Sender: TObject);
    procedure PasteClick(Sender: TObject);
    procedure DeleteClick(Sender: TObject);
    procedure SelectallClick(Sender: TObject);
    procedure Bookmark1Click(Sender: TObject);
    procedure Bookmark11Click(Sender: TObject);
    procedure Bookmark21Click(Sender: TObject);
    procedure Bookmark31Click(Sender: TObject);
    procedure Bookmark41Click(Sender: TObject);
    procedure Bookmark51Click(Sender: TObject);
    procedure Bookmark61Click(Sender: TObject);
    procedure Bookmark71Click(Sender: TObject);
    procedure Bookmark81Click(Sender: TObject);
    procedure Bookmark91Click(Sender: TObject);
    procedure Bookmark01Click(Sender: TObject);
    procedure Bookmark12Click(Sender: TObject);
    procedure Bookmark22Click(Sender: TObject);
    procedure Bookmark32Click(Sender: TObject);
    procedure Bookmark42Click(Sender: TObject);
    procedure Bookmark52Click(Sender: TObject);
    procedure Bookmark62Click(Sender: TObject);
    procedure Bookmark72Click(Sender: TObject);
    procedure Bookmark82Click(Sender: TObject);
    procedure Bookmark92Click(Sender: TObject);
    procedure PopupMenu1Popup(Sender: TObject);
    procedure PacocSynEditChange(Sender: TObject);
    procedure PacocSynEditClick(Sender: TObject);
    procedure PacocSynEditKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure PacocSynEditMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure mnDebugClick(Sender: TObject);
    procedure SpeedButton1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure lbFunctionsMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
  private
    { Private declarations }
  public
  end;

  TPlugFunc = Record
    adress : Pointer;
    name : string;
  end;

  TPlugin = Record
    funcs : array of TPlugFunc;
    dllHandle : HMODULE;
    filename : string;
  end;

  TCollapsedLine = Record
    Lines: TStringList;
    Line: Integer;
  end;

  TProc = Record
    Line: Cardinal;
    Name: String;
    PFType: (proc, func);
    ReturnType: String;
    Forwarded: Boolean;
    Parameters: Array of Record
      ParamName: String;
      VarType: String;
    end;
  end;


var
  MainForm: TMainForm;
  RunThread : TPacocThread;   //The script thread
  plugins : array of TPlugin; //Array with all the plugins ;)
  plugcount : integer;        //The amount of plugins
  ClientDC : HDC;             //DC for the client
  Client: HWND;               //Client windowhandle
  ClientBox: TRect;           //The box (top, bottom etc.)
  ClientWdth, ClientHght: Integer; //The client's width and height
  LastCursor  : TCursor;      //Cursor, used in crosshair
  CTS : Integer = 1;          //Color tolerance speed
  BreakPoints: TIntegerArray; //Breakpoints...
  Paused: Boolean = False;    //Boolean to follow if the script is paused or not
  CollapsedLines: Array of TCollapsedLine; //Lists to keep track of collapsed code.  FUCK YOU SCINTILLIA!  SynEdit pwns you!
  LastLine, LastLineCount: Integer; //For keeping track of where collapsed code is
  MDown: Boolean = False;     //For the window selector
  LastRect: TRect;            //^
  LastHandle: HWND;           //^
  Procs: Array of TProc;      //The procedures/functions used in the script (custom only)

implementation

{$R *.dfm}
{$R WindowsXp.Res}

procedure ParseProcs;
var
  I, Start, foo: Integer;
  Str, ParamStr: String;

procedure ParseParam;
begin
  writeln(ParamStr);  //for testing.  Everything seems to work perfectly!
  //everything's in ParamStr.  Use Procs[High(Procs)].Parameters to add all of the parameters to
end;

begin
  SetLength(Procs, 0);
  Str:= MainForm.PacocSynEdit.Lines.Text;
  while Pos('''', Str) > 0 do
    if(PosEx('''', Str, Pos('''', Str) + 1) > 0)then
      Delete(Str, Pos('''', Str), min(PosEx('''', Str, Pos('''', Str) + 1) - Pos('''', Str) + 1, PosEx(chr(13), Str, Pos('''', Str) + 1) - Pos('''', Str)))
    else
      break;
  while Pos('//', Str) > 0 do
  begin
    if(PosEx(chr(13), Str, Pos('//', Str)) > 0)then
      Delete(Str, Pos('//', Str), PosEx(chr(13), Str, Pos('//', Str)) - Pos('//', Str))
    else
      break;
  while Pos('{', Str) > 0 do
    if(PosEx('}', Str, Pos('{', Str)) > 0)then
      Delete(Str, Pos('{', Str), PosEx('}', Str, Pos('{', Str)) - Pos('{', Str) + 1)
    else
      break;
  end;
  while Pos('  ', Str) > 0 do
    Str:= Replace(Str, '  ', ' ');
  while Pos(' (', Str) > 0 do
    Str:= Replace(Str, ' (', '(');
  I:= 0;
  while PosEx('function', Str, I) > 0 do
  begin
    ParamStr:= '';
    I:= PosEx('function', Str, I) + 7;
    SetLength(Procs, Length(Procs) + 1);
    Procs[High(Procs)].PFType:= func;
    repeat
      I:= I + 1;
    until(I > Length(Str)) or (Str[I] in ['A'..'z']) or (Str[I] = chr(13));
    if(I > Length(Str))then
    begin
      SetLength(Procs, High(Procs));
      break;
    end else if(Str[I] = chr(13))then
    begin
      SetLength(Procs, High(Procs));
      continue;
    end else begin
      Start:= I;
      while (Str[I] <> ';') and (Str[I] <> ':') and (Str[I] <> '(') and (Str[I] <> ' ') and (Str[I] <> chr(13)) and (I <> Length(Str)) do
        I:= I + 1;
      if(I = Length(Str))then
      begin
        SetLength(Procs, High(Procs));
        break;
      end;
      Procs[High(Procs)].Name:= copy(Str, Start, I - Start);
      if(Str[I] = '(')then
      begin
        foo:= I;
        while (Str[I] <> ')') and (I <> Length(Str)) do
          I:= I + 1;
      end;
      while (Str[I] <> ':') and (Str[I] <> chr(13)) and (I <> Length(Str)) do
        I:= I + 1;
      if(Str[I] = chr(13))then continue;
      if(I = Length(Str))then
      begin
        SetLength(Procs, High(Procs));
        break;
      end;
      while not(Str[I] in ['A'..'z']) and (Str[I] <> chr(13)) and (I <> Length(Str)) do
        I:= I + 1;
      if(I = Length(Str))then
      begin
        SetLength(Procs, High(Procs));
        break;
      end;
      if(Str[I] = chr(13))then continue;
      Start:= I;
      while (Str[I] <> ';') and (Str[I] <> chr(13)) and (I <> Length(Str)) do
        I:= I + 1;
      if(I = Length(Str))then
      begin
        SetLength(Procs, High(Procs));
        break;
      end;
      Procs[High(Procs)].ReturnType:= copy(Str, Start, I - Start);
    end;
    Start:= foo;
    foo:= I;
    I:= Start;
    while (Str[I] <> '(') and (I <> Length(Str)) and (Str[I] <> chr(13)) do
      I:= I + 1;
    if(Str[I] = '(')then
    begin
      while (Str[I] <> ')') and (Str[I] <> chr(13)) and (I <> Length(Str)) do
        I:= I + 1;
      if(Str[I] = ')')then
        ParamStr:= copy(Str, Start, I - Start + 1);
    end;
    I:= Start;
    if(ParamStr <> '')then
      ParseParam;
  end;

  I:= 0;
  while PosEx('procedure', Str, I) > 0 do
  begin
    ParamStr:= '';
    I:= PosEx('procedure', Str, I) + 8;
    SetLength(Procs, Length(Procs) + 1);
    Procs[High(Procs)].PFType:= proc;
    repeat
      I:= I + 1;
    until(I > Length(Str)) or (Str[I] in ['A'..'z']) or (Str[I] = chr(13));
    if(I > Length(Str))then
    begin
      SetLength(Procs, High(Procs));
      break;
    end else if(Str[I] = chr(13))then
    begin
      SetLength(Procs, High(Procs));
      continue;
    end else begin
      Start:= I;
      while (Str[I] <> ';') and (Str[I] <> ':') and (Str[I] <> '(') and (Str[I] <> ' ') and (Str[I] <> chr(13)) and (I <> Length(Str)) do
        I:= I + 1;
      if(I = Length(Str))then
      begin
        SetLength(Procs, High(Procs));
        break;
      end;
      if(Str[I] = '(')then
      begin
        foo:= Start;
        Start:= I;
        while (Str[I] <> ')') and (Str[I] <> chr(13)) and (I <> Length(Str)) do
          I:= I + 1;
        if(Str[I] = ')')then
          ParamStr:= copy(Str, Start, I - Start + 1);
        I:= Start;
        Start:= foo;
      end;
      Procs[High(Procs)].Name:= copy(Str, Start, I - Start);
    end;
    if(ParamStr <> '')then
      ParseParam;
  end;

  I:= foo;

  MainForm.lbFunctions.Clear;
  for I:= 0 to High(Procs) do
    MainForm.lbFunctions.Items.Add(Procs[I].Name);
end;

procedure TPacocThread.Execute;
begin
  if MainForm.Ce.Execute then
    PacocUI.WriteLn('Successfully executed')
  else
    PacocUI.WriteLn('[Runtime Error] : ' + MainForm.Ce.ExecErrorToString + ' in line ' +
                    inttostr(MainForm.ce.ExecErrorRow) + ' in script ' + MainForm.ce.ExecErrorFileName);
end;

procedure MoveMouse(x, y: Integer);
begin
  SetCursorPos(x + ClientBox.Left, y + ClientBox.Top);
end;

procedure ClickMouse(x, y: Integer; Left: Boolean);
begin
  x:= x + ClientBox.Left;
  y:= y + ClientBox.Top;
  if(Left)then
  begin
    mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
    mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0);
  end else begin
    mouse_event(MOUSEEVENTF_RIGHTDOWN, x, y, 0, 0);
    mouse_event(MOUSEEVENTF_RIGHTUP, x, y, 0, 0);
  end;
end;

procedure HoldMouse(x, y: Integer; Left: Boolean);
begin
  x:= x + ClientBox.Left;
  y:= y + ClientBox.Top;
  if(Left)then
    mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0)
  else
    mouse_event(MOUSEEVENTF_RIGHTDOWN, x, y, 0, 0);
end;

procedure ReleaseMouse(x, y: Integer; Left: Boolean);
begin
  x:= x + ClientBox.Left;
  y:= y + ClientBox.Top;
  if(Left)then
    mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0)
  else
    mouse_event(MOUSEEVENTF_RIGHTUP, x, y, 0, 0);
end;

procedure Wait(MS: Cardinal);
var
  T: Cardinal;
begin
  T:= GetTickCount;
  while GetTickCount - T < MS do
  begin
    sleep(1);
    Application.ProcessMessages;
  end;
end;

procedure Sleep(MS: Cardinal);
begin
  wait(MS);
end;

procedure TMainForm.btnRunClick(Sender: TObject);
var
  compiled: boolean;
  i : integer;
begin
  if(Paused)then
  begin
    Paused:= False;
    RunThread.Resume;
    exit;
  end;
  if ce.Running then
    exit;

  //if (RunThread = nil) then
  RunThread := TPacocThread.Create(true);
  ce.Script := PacocSynEdit.Lines;
  for i:= 0 to High(BreakPoints) do
    ce.SetBreakPoint(ce.MainFileName, BreakPoints[i]);
  Compiled := Ce.Compile;
  ce.FillMethods;
//  PacocUI.WriteLn(ce.MethodList.MethodName(ce.MethodList.Methods[0]));
  for i := 0 to ce.CompilerMessageCount -1 do
    PacocUI.WriteLn(ce.CompilerMessages[i].MessageToString);
  if Compiled then
    PacocUI.WriteLn('Successfully compiled'{+inttostr(ce.Comp.TypeList.Count)+' types!'});
  //for i := 0 to ce.Comp.TypeList.Count-1 do  //Type list dumping
  //PacocUI.WriteLn(ce.comp.TypeList.Strings[i]);
     // PacocUI.WriteLn(ce.Exec.ProcNames.Items[i]);
  if Compiled then
    RunThread.Resume
  else
    RunThread.Destroy;
end;

function GetSelf : TForm;
begin
  Result:= MainForm;
end;

procedure TerminateScript;
begin
  If MainForm.ce.Running then
    MainForm.ce.Stop;
end;

procedure TMainForm.HandlePlugins(ce : TPSScript);
var
  FileSearcher : TSearchRec; //Used to search for the DLL files ;)
  s : string;      //Holds current directory
  i, ii : integer; //For loop variables
  pntrArrc : function : integer; stdcall; //Pointer to GetFunctionCount;
  GetFuncInfo : function (x: Integer; var ProcAddr: Pointer; var ProcDef: PChar) : Integer; stdcall; //Pointer to GetFunctionInfo
  PD : PChar;     //Procedure Description
  pntr : Pointer; //Some random pointer (to the procedure)
  al : boolean;   //AL = Already Loaded
  arrc : integer; //ARRay Count
begin
  {$IfDef Debug}
  PacocUI.WriteLn('ownd');
  {$EndIf}
  al := false;
  pd := StrAlloc(255); //Allocate memory to the PChar
  s := GetCurrentDir;
  SetCurrentDir(ExtractFilePath(Application.ExeName)+'plugins\'); //Set current directory to plugin dir
  if FindFirst('*.dll', faAnyFile, FileSearcher) <> 0 then   //Search for DLL files
  begin
    SetCurrentDir(s);   //If no DLL's found, reset current directory
    exit;               //And exit;
  end;
  {$IfDef Debug}
  PacocUI.WriteLn('ua');
  {$EndIf}
  for i := 0 to high(plugins) do //Check if the plugin is already loaded
  begin
    {$IfDef Debug}
    PacocUI.WriteLn('checkin '+plugins[i].filename);
    {$EndIf}
    if plugins[i].filename = FileSearcher.Name then //If plugin filename = found DLL then
    begin
      AL := true; //Already loaded = true
      break;      //And stop searching :)
    end;
  end;
  if (not(AL)) then   //If plugin isnt loaded
  begin
    Inc(plugcount);   //Increment plugin count
    SetLength(plugins, plugcount); //Resize the array
    {$IfDef Debug}
    PacocUI.WriteLn(GetCurrentDir+'\'+FileSearcher.Name);
    {$EndIf}
    plugins[plugcount-1].dllHandle := LoadLibrary(PChar(GetCurrentDir+'\'+FileSearcher.Name)); //Use LoadLibrary to load the DLL
    if (plugins[plugcount-1].dllhandle <= 31) then //If not loaded correctly exit
    begin
      PacocUI.WriteLn('FAILED LOADING THE PLUGIN');
      Dec(plugcount);               //Decrease plugin count
      SetLength(plugins, plugcount);//Shorten the array
    end else
    begin
      pntrArrc := GetProcAddress(plugins[plugcount-1].dllhandle, PChar('GetFunctionCount')); //Assign the pointer
      {$IfDef Debug}
      PacocUI.WriteLn(inttostr(pntrArrc())+' functions!');
      {$EndIf}
      Arrc := pntrArrc();//Store array count
      Plugins[plugcount-1].filename := FileSearcher.Name; //Set plugin filename
      @GetFuncInfo := GetProcAddress(plugins[plugcount-1].dllhandle, PChar('GetFunctionInfo')); //Get the GetFunctionInfo Pointer
      SetLength(plugins[plugcount-1].funcs, ArrC); //Set the function array
      for i := 0 to ArrC-1 do  //For every function do
      begin
        if (GetFuncInfo(i, pntr, pd) < 0) then  //If function is invalid
          Continue;                             //Skip this function
        Plugins[plugcount-1].funcs[i].adress := pntr; //Set the pointer
        Plugins[plugcount-1].funcs[i].name := pd;     //And the name
        //ce.AddFunctionEx(pntr, string(PD), CdStdCall);
        //PacocUI.WriteLn('Added function '+string(pd));
      end;
    end;
  end;
  repeat                         //See above for comments
    if FindNext(FileSearcher) <> 0 then Break;  //if no more plugins found break
    al := false;
    for i := 0 to high(plugins) do
    begin
      //PacocUI.WriteLn('checkin '+plugins[i].filename);
      if plugins[i].filename = FileSearcher.Name then
      begin
        AL := true;
        break;
      end;
    end;
    if (not(AL)) then
    begin
      Inc(plugcount);
      SetLength(plugins, plugcount);
      PacocUI.WriteLn(GetCurrentDir+'\'+FileSearcher.Name);
      plugins[plugcount-1].dllHandle := LoadLibrary(PChar(GetCurrentDir+'\'+FileSearcher.Name));
      if (plugins[plugcount-1].dllhandle <= 0) then
      begin
        PacocUI.WriteLn('FAILED LOADING THE PLUGIN');
        Dec(plugcount);
        SetLength(plugins, plugcount);
      end else
      begin
        pntrArrc := GetProcAddress(plugins[plugcount-1].dllhandle, PChar('GetFunctionCount'));
        PacocUI.WriteLn(inttostr(pntrArrc())+' functions!');
        Arrc := pntrArrc();
        Plugins[plugcount-1].filename := FileSearcher.Name;
        @GetFuncInfo := GetProcAddress(plugins[plugcount-1].dllhandle, PChar('GetFunctionInfo'));
        SetLength(plugins[plugcount-1].funcs, ArrC);
        for i := 0 to ArrC-1 do
        begin
          if (GetFuncInfo(i, pntr, pd) < 0) then
            Continue;
          Plugins[plugcount-1].funcs[i].adress := pntr;
          Plugins[plugcount-1].funcs[i].name := pd;
        end;
      end;
    end;
  until false;

  for i := 0 to plugcount-1 do  //For every plugin
    for ii := 0 to length(plugins[i].funcs)-1 do //For every function in it
    begin
      ce.AddFunctionEx(plugins[i].funcs[ii].adress, plugins[i].funcs[ii].name, CdStdCall); //Add function to the engine
      {$IfDef Debug}
      PacocUI.WriteLn('ADDED FUNCTION '+plugins[i].funcs[ii].name); //PacocUI.WriteLn function name
      {$EndIf}
    end;
  StrDispose(pd); //Free the PChar
  //Form1.PacocUI.WriteLn(inttostr(i)+', '+inttostr(length(plugins)));
end;

procedure TMainForm.ceCompile(Sender: TPSScript);
begin
  ce.Comp.AddTypeS('TPointArray', 'array of TPoint;');
  ce.Comp.AddTypeS('T2DPointArray', 'array of TPointArray');
  ce.Comp.AddTypeS('TBox', 'record x1, y1, x2, y2: Integer; end;');
  ce.Comp.AddTypeS('TIntegerArray', 'array of Integer');
  ce.Comp.AddTypeS('TExtendedArray', 'array of Extended');
  ce.Comp.AddTypeS('TStringArray', 'array of String');
  ce.AddFunction(@PacocUI.WriteLn, 'procedure WriteLn(s : string);');
  ce.AddFunction(@PacocUI.ClearDebug, 'procedure ClearDebug;');
  ce.AddFunction(@PacocUI.ShowMessage, 'procedure ShowMessage(Msg: String);');
  ce.AddFunction(@PacocUI.DisplayDebugImgWindow, 'procedure DisplayDebugImgWindow(Width, Height: Integer);');
  ce.AddFunction(@PacocUI.GetDebugCanvas, 'function GetDebugCanvas: TCanvas;');
  ce.AddFunction(@PacocMaths.Square, 'function Sqr(X: Extended): Extended;');
  ce.AddFunction(@PacocMaths.SqrRoot, 'function  Sqrt(e : Extended): Extended;');
  ce.AddFunction(@PacocMaths.Rndm, 'function Random(I: Integer): Integer;');
  ce.AddFunction(@PacocMaths.RndmRange, 'function RandomRange(iFrom, iTo: Integer): Integer;');
  ce.AddFunction(@PacocMaths.Pow, 'function Pow(Base, Exponent: Extended): Extended;');
  ce.AddFunction(@PacocMaths.IntPow, 'function IntPow(Base: Extended; Exponent: Integer): Extended;');
  ce.AddFunction(@PacocMaths.Maximum, 'function MaxE(N1, N2: Extended): Extended;');
  ce.AddFunction(@PacocMaths.Minimum, 'function MinE(N1, N2: Extended): Extended;');
  ce.AddFunction(@PacocMaths.iMaximum, 'function Max(N1, N2: Integer): Integer;');
  ce.AddFunction(@PacocMaths.iMinimum, 'function Min(N1, N2: Integer): Integer;');
  ce.AddFunction(@PacocMaths.Int, 'function Int(E: Extended): Integer;');
  ce.AddFunction(@PacocMaths.Flr, 'function Floor(E: Extended): Integer;');
  ce.AddFunction(@PacocMaths.Cel, 'function Ceil(E: Extended): Integer;');
  ce.AddFunction(@PacocMaths.Trnc, 'function Trunc(E: Extended): Integer;');
  ce.AddFunction(@PacocMaths.iAbsVal, 'function iAbs(I: Integer): Integer;');
  ce.AddFunction(@PacocMaths.Distance, 'function Distance(x1, y1, x2, y2: Integer): Integer;');
  ce.AddFunction(@PacocMaths.IntInBox, 'function IntInBox(x, y: Integer; Box: TBox): Boolean;');
  ce.AddFunction(@PacocMaths.PointInBox, 'function PointInBox(P: TPoint; Box: TBox): Boolean;');
  ce.AddFunction(@PacocMaths.PointToBox, 'function PointToBox(P1, P2: TPoint): TBox;');
  ce.AddFunction(@PacocMaths.Point, 'function Point(x, y: Integer): TPoint;');
  ce.AddFunction(@PacocMaths.IntToBox, 'function IntToBox(x1, y1, x2, y2: Integer; Box: TBox): TBox;');
  ce.AddFunction(@PacocMaths.AMin, 'function AMin(Data: TIntegerArray): Integer;');
  ce.AddFunction(@PacocMaths.AMinE, 'function AMinE(Data: TExtendedArray): Extended;');
  ce.AddFunction(@PacocMaths.AMax, 'function AMax(Data: TIntegerArray): Integer;');
  ce.AddFunction(@PacocMaths.AMaxE, 'function AMaxE(Data: TExtendedArray): Extended;');
  ce.AddFunction(@PacocStringManipulation.Replace, 'function Replace(Text, FindStr, ReplaceStr: string): string;');
  ce.AddFunction(@PacocStringManipulation.GetNumbers, 'function GetNumbers(Text: string): string;');
  ce.AddFunction(@PacocStringManipulation.GetLetters, 'function GetLetters(Text: String): String;');
  ce.AddFunction(@PacocStringManipulation.TrimNumbers, 'function TrimNumbers(Text: String): String;');
  ce.AddFunction(@PacocStringManipulation.TrimLetters, 'function TrimLetters(Text: String): String;');
  ce.AddFunction(@PacocStringManipulation.GetOthers, 'function GetOthers(Text: String): String;');
  ce.AddFunction(@PacocStringManipulation.TrimOthers, 'function TrimOthers(Text: String): String;');
  ce.AddFunction(@PacocStringManipulation.Capitalize, 'function Capitalize(S: String): String;');
  ce.AddFunction(@PacocStringManipulation.PosEx, 'function PosEx(Search, S: String; From: Integer): Integer;');
  ce.AddFunction(@PacocStringManipulation.Delete, 'procedure Delete(var s: string; ifrom, icount: LongInt);');
  ce.AddFunction(@TerminateScript, 'procedure TerminateScript;');
  ce.AddFunction(@MoveMouse, 'procedure MoveMouse(x, y: Integer);');
  ce.AddFunction(@ClickMouse, 'procedure ClickMouse(x, y: Integer; Left: Boolean);');
  ce.AddFunction(@HoldMouse, 'procedure HoldMouse(x, y: Integer; Left: Boolean);');
  ce.AddFunction(@ReleaseMouse, 'procedure ReleaseMouse(x, y: Integer; Left: Boolean);');
  ce.AddFunction(@Wait, 'procedure Wait(MS: Integer);');
  ce.AddFunction(@Sleep, 'procedure Sleep(MS: Integer);');
  ce.AddFunction(@GetTickCount, 'function GetSystemTime: Integer');
  ce.AddFunction(@GetTickCount, 'function GetTickCount: Integer');
  ce.AddFunction(@PacocColourFinders.FindColor, 'function FindColor(var x, y: Integer; color, xs, ys, xe, ye: Integer): Boolean;');
  ce.AddFunction(@PacocColourFinders.GetColor, 'function GetColor(x, y: Integer): Integer;');
  ce.AddFunction(@PacocInput.GetMousePos, 'procedure GetMousePos(var x, y: Integer);');
  ce.AddFunction(@PacocInput.ActivateClient, 'procedure ActivateClient;');
  ce.AddFunction(@PacocInput.GetClientWindowHandle, 'function GetClientWindowHandle: Integer');
  ce.AddFunction(@PacocInput.SetClientWindowHandle, 'procedure SetClientWindowHandle(H: Integer);');
  ce.AddFunction(@PacocInput.SetDesktopAsClient, 'procedure SetDesktopAsClient;');
  ce.AddFunction(@PacocInput.SetTargetDC, 'procedure SetTargetDC(DC: Integer);');
  ce.AddFunction(@PacocInput.GetClientDimensions, 'procedure GetClientDimensions(var Width, Height: Integer);');
  ce.AddFunction(@PacocInput.GetKeyCode, 'function GetKeyCode(Key: Char): Byte;');
  ce.AddFunction(@PacocFileManipulation.OpenFileHandle, 'function  OpenFile(Path: String): Integer;');
  ce.AddFunction(@PacocFileManipulation.CloseFileHandle, 'procedure CloseFile(FileNum: Integer);');
  HandlePlugins(sender);                                    
  {PacocColourFinders.ClientBitmap.Canvas.Handle := ClientDC; }
end;

procedure TMainForm.mnF1QuitClick(Sender: TObject);
begin
  Application.Terminate;
end;

procedure TMainForm.About1Click(Sender: TObject);
begin
  aboutform.frmAbout.ShowModal;
end;

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
var
  i : integer;
begin
  if ce.Running then
    Ce.Stop;
  ReleaseDC(Client, ClientDC);
  for i := 0 to plugcount-1 do
    if (plugins[i].dllHandle > 0) then
      FreeLibrary(plugins[i].dllHandle);
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  Client:= 0;
  CTS:= 1;
  ClientDC:= GetWindowDC(0);
  ClientBox:= Screen.DesktopRect;
  ClientWdth:= Screen.Width;
  ClientHght:= Screen.Height;
  LastLine:= PacocSynEdit.CaretY;
  LastLineCount:= PacocSynEdit.Lines.Count;
  ParseProcs;
end;

procedure TMainForm.SpeedButton1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  DC: HDC;
  I: Integer;
  DrawCanvas : TCanvas;
begin
  if(Button <> mbLeft)then exit;   
  InvalidateRect(0, @LastRect, false);
  DrawCanvas := TCanvas.Create;
  Screen.Cursor:= LastCursor;
  ReleaseDC(Client, ClientDC);
  Client:= WindowFromPoint(Mouse.CursorPos); //Get the client handle
  ClientDC:= GetDC(Client);
  GetWindowRect(Client, ClientBox); //Get client position
  ClientWdth:= ClientBox.Right - ClientBox.Left;
  ClientHght:= ClientBox.Bottom - ClientBox.Top;
  PacocColourFinders.bw:= ClientWdth;
  PacocColourFinders.bh:= ClientHght;
  PacocColourFinders.SBMP.Width:= bw;
  PacocColourFinders.SBMP.Height:= bh;
  DC:= GetWindowDC(0); //Dekstop DC
  DrawCanvas.Handle:= DC;
  DrawCanvas.Pen.Mode:= pmNot; //If the current colour is dark, this will draw white, else black
  DrawCanvas.Pen.Width:= 5; //To make it a little bit thicker
  I:= 50;
  repeat
    DrawCanvas.Polyline([Point(ClientBox.Left - I, ClientBox.Top - I),
                         Point(ClientBox.Left - I, ClientBox.Bottom + I),
                         Point(ClientBox.Right + I, ClientBox.Bottom + I),
                         Point(ClientBox.Right + I, ClientBox.Top - I),
                         Point(ClientBox.Left - I, ClientBox.Top - I)]);
    wait(1);
    DrawCanvas.Polyline([Point(ClientBox.Left - I, ClientBox.Top - I),
                         Point(ClientBox.Left - I, ClientBox.Bottom + I),
                         Point(ClientBox.Right + I, ClientBox.Bottom + I),
                         Point(ClientBox.Right + I, ClientBox.Top - I),
                         Point(ClientBox.Left - I, ClientBox.Top - I)]);
    I:= I - 2;
  until(I = 0);
  ReleaseDC(0, DC);
  FreeAndNil(DrawCanvas);
  PacocUI.WriteLn('User specified a new client window');
  for I:= 0 to SBMP.Height - 1 do
  begin
    Scanlines[I]:= nil;
    Scanlines[I]:= SBMP.ScanLine[I];
  end;
  MDown:= False;
end;

procedure TMainForm.SpeedButton1MouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
var
  Wnd: hWnd;
  Rect: TRect;
  Can: TCanvas;
  DC: HDC;
begin
  if(not(MDown))then exit;
  Wnd:= WindowFromPoint(Mouse.CursorPos); //Get the handle of the window that is under the mouse
  GetWindowRect(Wnd, Rect); //We then get its dimensions and position
  Can:= TCanvas.Create; //Create a canvas to get the canvas of the screen
  DC:= GetWindowDC(0); //Get the DC of the screen
  Can.Handle:= DC; //Set the DC of the canvas to the DC of the screen
  Can.Pen.Mode:= pmCopy; //In case it's something else
  Can.Pen.Width:= 5; //Set the width
  Can.Pen.Color:= 255; //And the color
  if(LastHandle <> Wnd)then
//    RedrawWindow(LastHandle, @LastRect, 0, RDW_UPDATENOW	or RDW_INVALIDATE);
    InvalidateRect(0, @LastRect, false);
  Can.Polyline([Point(Rect.Left + 2, Rect.Top + 2), Point(Rect.Right - 3, Rect.Top + 2),
                Point(Rect.Right - 3, Rect.Bottom - 3), Point(Rect.Left + 2, Rect.Bottom - 3),
                Point(Rect.Left + 2, Rect.Top + 2)]); //Draw the red border
  Can.Free;
  LastRect:= Rect;
  LastRect.Left:= LastRect.Left - 5;
  LastRect.Top:= LastRect.Left - 5;
  LastRect.Right:= LastRect.Right + 5;
  LastRect.Bottom:= LastRect.Bottom + 5;
{  LastRect.Right:= LastRect.Right - LastRect.Left + 3;
  LastRect.Bottom:= LastRect.Bottom - LastRect.Top + 3;
  LastRect.Top:= 0;
  LastRect.Left:= 0; }
  LastHandle:= Wnd;
end;

procedure TMainForm.SpeedButton1MouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if(Button <> mbLeft)then exit;
  LastCursor:= Screen.Cursor;
  Screen.Cursor:= crCross;
  MDown:= True;
end;

procedure TMainForm.SpeedButton2Click(Sender: TObject);
var
  DC: HDC;
begin
  DC:= GetWindowDC(0);
  //DrawCanvas.Handle:= DC;
  clrPick.Width := screen.Width;
  clrPick.Height := screen.Height;
  BitBlt(clrPick.Image1.Canvas.Handle, 0, 0, screen.Width, screen.Height, DC, 0, 0, SRCCOPY);
  //PickColor.Form3.Image1.Canvas.CopyRect(PickColor.Form3.Image1.ClientRect, DrawCanvas, DrawCanvas.ClipRect);
  clrPick.Show;
  ReleaseDC(0, DC);
end;

function CanCollapse(Line: Integer): Boolean;
//var
//  Position: TBufferCoord;
//  S: String;
begin
{  Position.Char:= 0;
  Position.Line:= Line - 1;
  Result:= True;
  repeat
    S:= Lowercase(Form1.PacocSynEdit.GetWordAtRowCol(Form1.PacocSynEdit.PrevWordPosEx(Position)));
    Position:= Form1.PacocSynEdit.PrevWordPosEx(Position);
    Result:= not((S = 'begin') or (S = 'end'));
    if(Result)then
      if(S = 'procedure') or (S = 'function')then exit;
    Position.Char:= Position.Char - 1;
    if(Position.Char = -1)then
    begin
      Position.Line:= Position.Line - 1;
      Position.Char:= Length(Form1.PacocSynEdit.Lines.Strings[Position.Line]);
    end;
  until(not(Result))}
  Result:= (Pos(' procedure ', ' ' + Lowercase(MainForm.PacocSynEdit.Lines.Strings[Line - 2])) > 0) or
           (Pos(' function ', ' ' + Lowercase(MainForm.PacocSynEdit.Lines.Strings[Line - 2])) > 0);
end;

procedure TMainForm.PacocSynEditGutterClick(Sender: TObject;
  Button: TMouseButton; X, Y, Line: Integer; Mark: TSynEditMark);
var
  I, II, Begins: Integer;
begin
  if(x <= 20)then
    begin
    for I:= 0 to High(BreakPoints) do
      if(BreakPoints[I] = Line)then break;
    if(I = Length(BreakPoints)) or (Length(BreakPoints) = 0)then
    begin
      SetLength(BreakPoints, Length(BreakPoints) + 1);
      BreakPoints[High(BreakPoints)]:= Line;
    end else begin
      BreakPoints[I]:= BreakPoints[High(BreakPoints)];
      SetLength(BreakPoints, High(BreakPoints));
    end;
  end else begin
    for I:= 0 to High(CollapsedLines) do
      if(CollapsedLines[I].Line = Line)then
      begin
        for II:= CollapsedLines[I].Lines.Count - 1 downto 0 do
          PacocSynEdit.Lines.Insert(Line, CollapsedLines[I].Lines.Strings[II]);
        for II:= 0 to High(CollapsedLines) do
          if(CollapsedLines[II].Line > CollapsedLines[I].Line)then
            CollapsedLines[II].Line:= CollapsedLines[II].Line + CollapsedLines[I].Lines.Count;
        CollapsedLines[I]:= CollapsedLines[High(CollapsedLines)];
        SetLength(CollapsedLines, High(CollapsedLines));
        exit;
      end;
    if(CanCollapse(Line))then
    begin
      SetLength(CollapsedLines, Length(CollapsedLines) + 1);
      CollapsedLines[High(CollapsedLines)].Lines:= TStringList.Create;
      CollapsedLines[High(CollapsedLines)].Line:= Line;
      if(Lowercase(PacocSynEdit.Lines.Strings[Line - 1][1]) = 'b')then
        Begins:= 1
      else
        Begins:= 0;
      repeat
        if(Lowercase(PacocSynEdit.GetWordAtRowCol(PacocSynEdit.NextWordPos)) = 'begin')then
          Begins:= Begins + 1
        else if(Lowercase(PacocSynEdit.GetWordAtRowCol(PacocSynEdit.NextWordPos)) = 'end')then
          Begins:= Begins - 1;
        PacocSynEdit.CaretXY:= PacocSynEdit.WordEndEx(PacocSynEdit.NextWordPos);
      until(Begins = 0);
      I:= PacocSynEdit.CaretY;
      for II:= Line to I - 2 do
        CollapsedLines[High(CollapsedLines)].Lines.Add(PacocSynEdit.Lines.Strings[II]);
      for II:= 0 to High(CollapsedLines) - 1 do
        if(CollapsedLines[II].Line > I)then
          CollapsedLines[II].Line:= CollapsedLines[II].Line - ((I - 1) - (Line));
      for II:= Line + 1 to I - 1 do
        PacocSynEdit.Lines.Delete(Line);
      PacocSynEdit.CaretX:= 0;
      PacocSynEdit.CaretY:= Line;
    end;
  end;
end;

procedure TMainForm.ceBreakpoint(Sender: TObject; const FileName: String;
  Position, Row, Col: Cardinal);
var
  I: Integer;
  S: String;
begin
  Paused:= True;
  ce.ClearBreakPoint(ce.MainFileName, Row);
  if(MessageBox(Self.Handle, PChar('We have hit a breakpoint on line ' + inttostr(Row) + '.  Would you like to see the current memory?'), 'Breakpoint', MB_YESNO) = mrYes)then
  begin
    if(ce.Exec.GlobalVarNames.Count > 0)then
    begin
      S:= 'Global variables:' + #10#13;
      for I:= 0 to ce.Exec.GlobalVarNames.Count - 1 do
        S:= S + ce.Exec.GlobalVarNames.Items[I] + ' = ' + ce.GetVarContents(ce.Exec.GlobalVarNames.Items[I]) + #10#13;
    end;
    if(ce.Exec.CurrentProcVars.Count > 0)then
    begin
      S:= S + #10#13 + 'Procedure/function variables:' + #10#13;
      for I:= 0 to ce.Exec.CurrentProcVars.Count - 1 do
        S:= S + ce.Exec.CurrentProcVars.Items[I] + ' = ' + ce.GetVarContents(ce.Exec.CurrentProcVars.Items[I]) + #10#13;
    end;
    S:= System.Copy(S, 1, Length(S) - 2);
    MessageBox(Self.Handle, PChar(S), 'Memory', MB_OK);
  end;
  RunThread.Suspend;
  //  ShowMessage('We have stopped at line ' + inttostr(Row) + ', which reads:'#10#13 + ce.Script.Strings[Row - 1]);
end;

procedure TMainForm.PacocSynEditMouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
{var
  S: String;
  Strs: Array of String;
  I, LS: Integer;
  Poz, Row, Col: Cardinal;
  Func: String;}
begin
  if(ce.Running)then
  begin
//    if(Length(PacocSynEdit.SelText) < 2)then
//    begin
      if(ce.GetVarContents(PacocSynEdit.WordAtMouse) <> '')then if(ce.GetVarContents(PacocSynEdit.WordAtMouse) <> 'Unknown Identifier')then
      begin
        ShowHint:= False;
        ShowHint:= True;
        ce.GetVarContents(PacocSynEdit.WordAtMouse);
        exit;
      end;
   { end else begin
      S:= PacocSynEdit.SelText;
      while Pos('  ', S) > 0 do
        S:= Replace(S, '  ', ' ');
      S:= Replace(Lowercase(S), ' div ', ' / ');
      S:= Replace(S, ' +', '+');
      S:= Replace(S, ' -', '-');
      S:= Replace(S, ' /', '/');
      S:= Replace(S, ' *', '*');
      S:= Replace(S, '+ ', '+');
      S:= Replace(S, '- ', '-');
      S:= Replace(S, '/ ', '/');
      S:= Replace(S, '* ', '*');
      LS:= 1;
      for I:= 1 to Length(S) do
      begin
        if(S[I] = ' ') or (S[I] = '+') or (S[I] = '-') or (S[I] = '/') or (S[I] = '*')then
        begin
          SetLength(Strs, Length(Strs) + 1);
          Strs[High(Strs)]:= System.Copy(S, LS, I - LS);
          if(S[I] = '+') or (S[I] = '-') or (S[I] = '/') or (S[I] = '*')then
          begin
            SetLength(Strs, Length(Strs) + 1);
            Strs[High(Strs)]:= S[I];
          end else exit;
          LS:= I;
        end;
      end;
      SetLength(Strs, Length(Strs) + 1);
      Strs[High(Strs)]:= System.Copy(S, LS + 1, Length(S));
      //must now parse and calculate what's in Strs
    end;}
  end;
  ShowHint:= False;
end;

procedure TMainForm.btnPauseClick(Sender: TObject);
begin
  if(not(Paused))then
  begin
    Paused:= True;
    RunThread.Suspend;
  end;
end;

procedure TMainForm.btnStopClick(Sender: TObject);
begin
  if(ce.Running)then
  begin
//    RunThread.Execute;
    ce.Stop;
  end else if(Paused)then
  begin
    Paused:= False;
//    RunThread.Resume;
//    RunThread.Execute;
    ce.Stop;
  end;
end;

procedure TMainForm.PacocSynEditDblClick(Sender: TObject);
var
  P1, P2: TBufferCoord;
  SelStart, SelEnd: Integer;
begin
  if(PacocSynEdit.SelLength > 0)then exit;
  P1:= PacocSynEdit.PrevWordPos;
  P2:= PacocSynEdit.NextWordPos;
  if(P1.Line = PacocSynEdit.CaretY)then
  begin
    if(P2.Line = PacocSynEdit.CaretY)then
    begin
      if(abs(PacocSynEdit.CaretX - P1.Char) < abs(PacocSynEdit.CaretX - P2.Char)) or (PacocSynEdit.Lines.Count = PacocSynEdit.CaretY)then
      begin
        SelStart:= PacocSynEdit.RowColToCharIndex(PacocSynEdit.PrevWordPos);
        SelEnd:= PacocSynEdit.RowColToCharIndex(PacocSynEdit.WordEndEx(PacocSynEdit.PrevWordPos));
        PacocSynEdit.SelStart:= SelStart;
        PacocSynEdit.SelEnd:= SelEnd;
      end else begin
        SelStart:= PacocSynEdit.RowColToCharIndex(PacocSynEdit.NextWordPos);
        SelEnd:= PacocSynEdit.RowColToCharIndex(PacocSynEdit.WordEndEx(PacocSynEdit.NextWordPos));
        PacocSynEdit.SelStart:= SelStart;
        PacocSynEdit.SelEnd:= SelEnd;
      end;
    end else begin
      SelStart:= PacocSynEdit.RowColToCharIndex(PacocSynEdit.PrevWordPos);
      SelEnd:= PacocSynEdit.RowColToCharIndex(PacocSynEdit.WordEndEx(PacocSynEdit.PrevWordPos));
      PacocSynEdit.SelStart:= SelStart;
      PacocSynEdit.SelEnd:= SelEnd;
    end;
  end else if(P2.Line = PacocSynEdit.CaretY)then
  begin
    SelStart:= PacocSynEdit.RowColToCharIndex(PacocSynEdit.NextWordPos);
    SelEnd:= PacocSynEdit.RowColToCharIndex(PacocSynEdit.WordEndEx(PacocSynEdit.NextWordPos));
    PacocSynEdit.SelStart:= SelStart;
    PacocSynEdit.SelEnd:= SelEnd;
  end;
end;

procedure TMainForm.UndoClick(Sender: TObject);
begin
  PacocSynEdit.Undo;
end;

procedure TMainForm.RedoClick(Sender: TObject);
begin
  PacocSynEdit.Redo;
end;

procedure TMainForm.CutClick(Sender: TObject);
begin
  PacocSynEdit.CutToClipboard;
end;

procedure TMainForm.CopyClick(Sender: TObject);
begin
  PacocSynEdit.CopyToClipboard;
end;

procedure TMainForm.PasteClick(Sender: TObject);
begin
  PacocSynEdit.PasteFromClipboard;
end;

procedure TMainForm.DeleteClick(Sender: TObject);
begin
  PacocSynEdit.SelText:= '';
end;

procedure TMainForm.SelectallClick(Sender: TObject);
begin
  PacocSynEdit.SelectAll;
end;

procedure TMainForm.Bookmark1Click(Sender: TObject);
begin
  if(not(PacocSynEdit.IsBookmark(0)))then
    PacocSynEdit.SetBookMark(0, PacocSynEdit.CaretX, PacocSynEdit.CaretY)
  else
    PacocSynEdit.ClearBookmark(0);
end;

procedure TMainForm.Bookmark11Click(Sender: TObject);
begin
  if(not(PacocSynEdit.IsBookmark(1)))then
    PacocSynEdit.SetBookMark(1, PacocSynEdit.CaretX, PacocSynEdit.CaretY)
  else
    PacocSynEdit.ClearBookmark(1);
end;

procedure TMainForm.Bookmark21Click(Sender: TObject);
begin
  if(not(PacocSynEdit.IsBookmark(2)))then
    PacocSynEdit.SetBookMark(2, PacocSynEdit.CaretX, PacocSynEdit.CaretY)
  else
    PacocSynEdit.ClearBookmark(2);
end;

procedure TMainForm.Bookmark31Click(Sender: TObject);
begin
  if(not(PacocSynEdit.IsBookmark(3)))then
    PacocSynEdit.SetBookMark(3, PacocSynEdit.CaretX, PacocSynEdit.CaretY)
  else
    PacocSynEdit.ClearBookmark(3);
end;

procedure TMainForm.Bookmark41Click(Sender: TObject);
begin
  if(not(PacocSynEdit.IsBookmark(4)))then
    PacocSynEdit.SetBookMark(4, PacocSynEdit.CaretX, PacocSynEdit.CaretY)
  else
    PacocSynEdit.ClearBookmark(4);
end;

procedure TMainForm.Bookmark51Click(Sender: TObject);
begin
  if(not(PacocSynEdit.IsBookmark(5)))then
    PacocSynEdit.SetBookMark(5, PacocSynEdit.CaretX, PacocSynEdit.CaretY)
  else
    PacocSynEdit.ClearBookmark(5);
end;

procedure TMainForm.Bookmark61Click(Sender: TObject);
begin
  if(not(PacocSynEdit.IsBookmark(6)))then
    PacocSynEdit.SetBookMark(6, PacocSynEdit.CaretX, PacocSynEdit.CaretY)
  else
    PacocSynEdit.ClearBookmark(6);
end;

procedure TMainForm.Bookmark71Click(Sender: TObject);
begin
  if(not(PacocSynEdit.IsBookmark(7)))then
    PacocSynEdit.SetBookMark(7, PacocSynEdit.CaretX, PacocSynEdit.CaretY)
  else
    PacocSynEdit.ClearBookmark(7);
end;

procedure TMainForm.Bookmark81Click(Sender: TObject);
begin
  if(not(PacocSynEdit.IsBookmark(8)))then
    PacocSynEdit.SetBookMark(8, PacocSynEdit.CaretX, PacocSynEdit.CaretY)
  else
    PacocSynEdit.ClearBookmark(8);
end;

procedure TMainForm.Bookmark91Click(Sender: TObject);
begin
  if(not(PacocSynEdit.IsBookmark(9)))then
    PacocSynEdit.SetBookMark(9, PacocSynEdit.CaretX, PacocSynEdit.CaretY)
  else
    PacocSynEdit.ClearBookmark(9);
end;

procedure TMainForm.Bookmark01Click(Sender: TObject);
begin
  PacocSynEdit.GotoBookmark(0);
end;

procedure TMainForm.Bookmark12Click(Sender: TObject);
begin
  PacocSynEdit.GotoBookmark(1);
end;

procedure TMainForm.Bookmark22Click(Sender: TObject);
begin
  PacocSynEdit.GotoBookmark(2);
end;

procedure TMainForm.Bookmark32Click(Sender: TObject);
begin
  PacocSynEdit.GotoBookmark(3);
end;

procedure TMainForm.Bookmark42Click(Sender: TObject);
begin
  PacocSynEdit.GotoBookmark(4);
end;

procedure TMainForm.Bookmark52Click(Sender: TObject);
begin
  PacocSynEdit.GotoBookmark(5);
end;

procedure TMainForm.Bookmark62Click(Sender: TObject);
begin
  PacocSynEdit.GotoBookmark(6);
end;

procedure TMainForm.Bookmark72Click(Sender: TObject);
begin
  PacocSynEdit.GotoBookmark(7);
end;

procedure TMainForm.Bookmark82Click(Sender: TObject);
begin
  PacocSynEdit.GotoBookmark(8);
end;

procedure TMainForm.Bookmark92Click(Sender: TObject);
begin
  PacocSynEdit.GotoBookmark(9);
end;

procedure TMainForm.PopupMenu1Popup(Sender: TObject);
begin
  with PopupMenu1 do
  begin
    Undo.Enabled:= PacocSynEdit.CanUndo;
    Redo.Enabled:= PacocSynEdit.CanRedo;
    Paste.Enabled:= PacocSynEdit.CanPaste;

    Cut.Enabled:= PacocSynEdit.SelLength > 0;
    Copy.Enabled:= PacocSynEdit.SelLength > 0;
    Delete.Enabled:= PacocSynEdit.SelLength > 0;

    Bookmark01.Enabled:= PacocSynEdit.IsBookmark(0);
    Bookmark12.Enabled:= PacocSynEdit.IsBookmark(1);
    Bookmark22.Enabled:= PacocSynEdit.IsBookmark(2);
    Bookmark32.Enabled:= PacocSynEdit.IsBookmark(3);
    Bookmark42.Enabled:= PacocSynEdit.IsBookmark(4);
    Bookmark52.Enabled:= PacocSynEdit.IsBookmark(5);
    Bookmark62.Enabled:= PacocSynEdit.IsBookmark(6);
    Bookmark72.Enabled:= PacocSynEdit.IsBookmark(7);
    Bookmark82.Enabled:= PacocSynEdit.IsBookmark(8);
    Bookmark92.Enabled:= PacocSynEdit.IsBookmark(9);

    Bookmark1.Checked:= PacocSynEdit.IsBookmark(0);
    Bookmark11.Checked:= PacocSynEdit.IsBookmark(1);
    Bookmark21.Checked:= PacocSynEdit.IsBookmark(2);
    Bookmark31.Checked:= PacocSynEdit.IsBookmark(3);
    Bookmark41.Checked:= PacocSynEdit.IsBookmark(4);
    Bookmark51.Checked:= PacocSynEdit.IsBookmark(5);
    Bookmark61.Checked:= PacocSynEdit.IsBookmark(6);
    Bookmark71.Checked:= PacocSynEdit.IsBookmark(7);
    Bookmark81.Checked:= PacocSynEdit.IsBookmark(8);
    Bookmark91.Checked:= PacocSynEdit.IsBookmark(9);
  end;
end;

procedure TMainForm.PacocSynEditChange(Sender: TObject);
var
  I, II, C: Integer;
  Swp: TCollapsedLine;
begin
  if(PacocSynEdit.CaretY <> LastLine) or (PacocSynEdit.Lines.Count <> LastLineCount)then
  begin
    I:= 0;
    II:= High(CollapsedLines);
    while I <= II do
    begin
      if((CollapsedLines[I].Line >= LastLine) and ((CollapsedLines[I].Line < PacocSynEdit.CaretY) or ((CollapsedLines[I].Line = PacocSynEdit.CaretY) and (PacocSynEdit.CaretX = 0)))) or //note for .CaretX = 0, I need to watch the first begin's position and substitute 0 for that
        ((CollapsedLines[I].Line <= LastLine) and ((CollapsedLines[I].Line > PacocSynEdit.CaretY) or ((CollapsedLines[I].Line = PacocSynEdit.CaretY) and (PacocSynEdit.CaretX = 0)))) and
        (LastLineCount > PacocSynEdit.Lines.Count)then
      begin
        if(Length(CollapsedLines) > 1)then
        begin
          for C:= I to High(CollapsedLines) - 1 do
          begin
            Swp:= CollapsedLines[C + 1];
            CollapsedLines[C + 1]:= CollapsedLines[C];
            CollapsedLines[C]:= Swp;
          end;
          SetLength(CollapsedLines, High(CollapsedLines));
        end else begin
          SetLength(CollapsedLines, 0);
          LastLineCount:= PacocSynEdit.Lines.Count;
          exit;
        end;
        II:= II - 1;
      end else if(CollapsedLines[I].Line >= LastLine)then
      begin
        CollapsedLines[I].Line:= CollapsedLines[I].Line + (PacocSynEdit.Lines.Count - LastLineCount);
        I:= I + 1;
      end else I:= I + 1;
    end;
  end else for I:= 0 to High(CollapsedLines) do
    if(CollapsedLines[I].Line = LastLine)then
    begin
      for II:= CollapsedLines[I].Lines.Count - 1 downto 0 do
        PacocSynEdit.Lines.Insert(LastLine, CollapsedLines[I].Lines.Strings[II]);
        for II:= 0 to High(CollapsedLines) do
          if(CollapsedLines[II].Line > CollapsedLines[I].Line)then
            CollapsedLines[II].Line:= CollapsedLines[II].Line + CollapsedLines[I].Lines.Count;
      CollapsedLines[I]:= CollapsedLines[High(CollapsedLines)];
      SetLength(CollapsedLines, High(CollapsedLines));
      Break;
    end;
  LastLineCount:= PacocSynEdit.Lines.Count;

  ParseProcs;
end;

procedure TMainForm.PacocSynEditClick(Sender: TObject);
begin
  if(PacocSynEdit.SelText <> '')then exit;
  LastLine:= PacocSynEdit.CaretY;
  LastLineCount:= PacocSynEdit.Lines.Count;
end;

procedure TMainForm.PacocSynEditKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
//  LastLine:= PacocSynEdit.CaretY;
//  LastLineCount:= PacocSynEdit.Lines.Count;
end;

procedure TMainForm.PacocSynEditMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  LastLine:= PacocSynEdit.CaretY;
end;

procedure TMainForm.mnDebugClick(Sender: TObject);
begin
  if(mnDebug.Checked)then
    frmDebug.Hide
  else
    frmDebug.Show;
end;

procedure TMainForm.lbFunctionsMouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
var
  Index, I: Integer;
begin
  Index:= lbFunctions.ItemAtPos(Point(x, y), True);
  if(Index < 0)then exit;
  case Procs[Index].PFType of
    proc: lbFunctions.Hint:= 'procedure ';
    func: lbFunctions.Hint:= 'function ';
  end;
  lbFunctions.Hint:= lbFunctions.Hint + Procs[Index].Name;
  if(Length(Procs[Index].Parameters) > 0)then
  begin
    lbFunctions.Hint:= lbFunctions.Hint + '(';
    for I:= 0 to High(Procs[Index].Parameters) do
    begin
      lbFunctions.Hint:= lbFunctions.Hint + Procs[Index].Parameters[I].ParamName + ': ' + Procs[Index].Parameters[I].VarType;
      if(I <> High(Procs[Index].Parameters))then
        lbFunctions.Hint:= lbFunctions.Hint + '; '
      else
        lbFunctions.Hint:= lbFunctions.Hint + ')';
    end;
  end;
  if(Procs[Index].PFType = func)then
    lbFunctions.Hint:= lbFunctions.Hint + ': ' + Procs[Index].ReturnType;
  lbFunctions.Hint:= lbFunctions.Hint + ';';
end;

end.
